package com.yxsk.relay.job.component.common.thread.observe;

import com.yxsk.relay.job.component.common.thread.Task;
import com.yxsk.relay.job.component.common.thread.lifecycle.ThreadLifecycle;

/**
 * @Author 11376
 * @CreaTime 2019/6/2 16:36
 * @Description 可观察的线程
 */
public final class ObservableThread<T> extends Thread implements Observable {

    private Task<T> task;

    private Cycle cycle;

    private ThreadLifecycle lifecycle;

    public ObservableThread(Task<T> task) {
        this(new ThreadLifecycle.DefaultThreadLifecycle(), task);
    }

    public ObservableThread(ThreadLifecycle lifecycle, Task<T> task) {
        this.task = task;
        this.cycle = Cycle.NEW;
        this.lifecycle = lifecycle;

        this.lifecycle.onNew();
    }

    @Override
    public Cycle getCycle() {
        return this.cycle;
    }

    @Override
    public Task<T> getTask() {
        return task;
    }

    @Override
    public void run() {
        // 启动任务
        this.updateCycle(Cycle.STARTED, null, null);
        try {
            // 运行任务
            this.updateCycle(Cycle.RUNNING, null, null);
            // 执行任务
            T result = this.task.execute();
            // 完成任务
            this.updateCycle(Cycle.FINISH, result, null);
        } catch (Exception e) {
            // 任务异常
            this.updateCycle(Cycle.ERROR, null, e);
        }
    }

    /**
     * @param cycle
     * @param result
     * @param e
     * @Author 11376
     * @Description 更新线程任务状态
     * @CreateTime 2019/6/2 17:08
     * @Return
     */
    private void updateCycle(Cycle cycle, T result, Exception e) {
        this.cycle = cycle;
        switch (cycle) {
            case STARTED:
                this.lifecycle.onStart(this);
                break;
            case RUNNING:
                this.lifecycle.onRunning(this);
                break;
            case FINISH:
                this.lifecycle.onFinish(this, result);
                break;
            case ERROR:
                this.lifecycle.onError(this, e);
                break;
            default:
                break;
        }
    }
}
